package com.lagou.mapper;

import com.lagou.sqlSession.DefaultSqlSession;
import com.lagou.sqlSession.SqlSession;
import com.lagou.sqlSession.SqlSessionFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.SQLException;
import java.util.List;

/**
 * @author: wudong
 * @create: 2021-05-31 14:46
 **/
public class SpringSqlSession extends DefaultSqlSession implements SqlSession {

    private final SqlSessionFactory sqlSessionFactory;

    private final SqlSession sqlSessionProxy;

    public SpringSqlSession(SqlSessionFactory sqlSessionFactory) {
        super(sqlSessionFactory.getConfiguration(),null);
        this.sqlSessionFactory = sqlSessionFactory;
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
                SqlSessionFactory.class.getClassLoader(),
                new Class[]{SqlSession.class},
                new SqlSessionInterceptor());
        ;
    }

    @Override
    public <E> List<E> selectList(String statementid, Object params) throws Exception {
        return sqlSessionProxy.selectList(statementid, params);
    }

    @Override
    public <T> T selectOne(String statementid, Object params) throws Exception {
        return sqlSessionProxy.selectOne(statementid, params);
    }

    @Override
    public int insert(String statement, Object parameter) throws Exception {
        return sqlSessionProxy.insert(statement, parameter);
    }

    @Override
    public int update(String statement, Object parameter) throws Exception {
        return sqlSessionProxy.update(statement, parameter);
    }

    @Override
    public int delete(String statement, Object parameter) throws Exception {
        return sqlSessionProxy.delete(statement, parameter);
    }

    @Override
    public void commit() throws SQLException {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");

    }

    @Override
    public void rollback() throws SQLException {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }

    @Override
    public void close() throws SQLException {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }


    private class SqlSessionInterceptor implements InvocationHandler {
        public SqlSessionInterceptor() {
            // Prevent Synthetic Access
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession autoSqlSession = null;
            try {
                autoSqlSession = SpringSqlSession.this.sqlSessionFactory.openSession();
                final Object result = method.invoke(autoSqlSession, args);
                autoSqlSession.commit();
                return result;
            } catch (Throwable t) {
                if (autoSqlSession != null) {
                    autoSqlSession.rollback();
                }
                throw new RuntimeException(t);
            } finally {
                if (autoSqlSession != null) {
                    autoSqlSession.close();
                }
            }
        }
    }
}
